﻿using AuditSample.Persistence;
using Microsoft.Activities.Extensions.Tracking;
using System;
using System.Activities;
using System.Activities.DurableInstancing;
using System.Activities.Statements;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Runtime.DurableInstancing;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AuditSample
{
    public class WorkFlowService
    {
        public Model1 dbContext = new Model1();

        internal static readonly AuditInvoice Workflow1Definition = new AuditInvoice();
        internal static readonly String ConnectionString = ConfigurationManager.ConnectionStrings["Model1"].ConnectionString;

        AutoResetEvent resetEvent;

        #region Fields
        /// <summary>
        ///   The is loaded.
        /// </summary>
        private bool isLoaded;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets Host.
        /// </summary>
        public WorkflowApplication Host { get; set; }

        /// <summary>
        ///   Gets Id.
        /// </summary>
        public Guid Id
        {
            get
            {
                return this.Host == null ? this.StateTracker.InstanceId : this.Host.Id;
            }
        }

        public String Type
        {
            get
            {
                return this.Host == null ? string.Empty : this.Host.WorkflowDefinition.DisplayName;
            }
        }

        /// <summary>
        ///   Gets or sets a value indicating whether IsLoaded.
        /// </summary>
        public bool IsLoaded
        {
            get
            {
                return this.isLoaded;
            }

            set
            {
                this.isLoaded = value;
            }
        }

        /// <summary>
        ///   Gets the StateTracker.
        /// </summary>
        public StateMachineStateTracker StateTracker { get; private set; }

        public HistoryTrackingParticipant HistoryTracking { get; private set; }


        public StateTrackingParticipant StateTracking { get; private set; }
        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkflowInstance"/> class.
        /// </summary>
        /// <param name="view">
        /// The view. 
        /// </param>
        /// <param name="stateMachineStateTracker">
        /// The StateTracker (optional) 
        /// </param>
        public WorkFlowService(StateMachineStateTracker stateMachineStateTracker = null, AutoResetEvent autoResetEvent = null)
        {
            this.StateTracker = stateMachineStateTracker ?? new StateMachineStateTracker(Workflow1Definition);
            this.resetEvent = autoResetEvent;
        }

        #endregion
        
        #region Methods

        /// <summary>
        ///   The create workflow application.
        /// </summary>
        private void CreateWorkflowApplication()
        {
            this.Host = new WorkflowApplication(Workflow1Definition)
            {
                InstanceStore = CreateInstanceStore(),
                PersistableIdle = delegate (WorkflowApplicationIdleEventArgs e)
                {
                    //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>();
                    // Outputs = ex.First().Outputs.ToString();
                    resetEvent.Set();
                    return PersistableIdleAction.Persist;
                },
                Completed = delegate (WorkflowApplicationCompletedEventArgs e)
                {
                    var instance = dbContext.WorkFlowInstances.FirstOrDefault(x => x.Id.Equals(e.InstanceId.ToString(), StringComparison.InvariantCultureIgnoreCase));
                    instance.IsCompleted = true;
                    dbContext.SaveChanges();
                    resetEvent.Set();
                },
                Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
                {
                    resetEvent.Set();
                },
                Unloaded = delegate (WorkflowApplicationEventArgs e)
                {
                    resetEvent.Set();
                },
                OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
                {
                    resetEvent.Set();
                    return UnhandledExceptionAction.Terminate;
                },
                Idle = delegate (WorkflowApplicationIdleEventArgs e)
                {
                    resetEvent.Set();
                    
                }
            };
            // Setup tracking in UI
             //this.Host.Extensions.Add(new MainWindow.TextTracker());
            this.Host.Extensions.Add(this.StateTracker);
            //this.Host.Extensions.Add(new CustomerPersistenceParticipant());
            //this.Host.Extensions.Add(new HistoryTrackingParticipant());

            // Setup the persistence participant
            this.Host.Extensions.Add(new StateTrackerPersistenceProvider(this.StateTracker));

            //this.Host.Extensions.Add(new StateParticipant());

            //this.Host.Extensions.Add(new HistoryTrackingParticipant_Old());
            if (this.HistoryTracking == null)
                this.HistoryTracking = new HistoryTrackingParticipant();
            if (this.StateTracking == null)
                this.StateTracking = new StateTrackingParticipant();
            this.Host.Extensions.Add(this.HistoryTracking);
            this.Host.Extensions.Add(this.StateTracking);

           
        }


        private InstanceStore CreateInstanceStore()
        {
            var conn = ConnectionString;
            var store = new SqlWorkflowInstanceStore(conn)
            {
                InstanceLockedExceptionAction = InstanceLockedExceptionAction.AggressiveRetry,
                InstanceCompletionAction = InstanceCompletionAction.DeleteNothing,
                HostLockRenewalPeriod = TimeSpan.FromSeconds(20),
                RunnableInstancesDetectionPeriod = TimeSpan.FromSeconds(3)
            };
            StateMachineStateTracker.Promote(store);
            var handle = store.CreateInstanceHandle();
            var view = store.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(60));
            store.DefaultInstanceOwner = view.InstanceOwner;

            handle.Free();

            return store;
        }
        #endregion
        
        #region Public Methods and Operators

        /// <summary>
        ///   The load.
        /// </summary>
        public void Load()
        {
            this.CreateWorkflowApplication();
            this.Host.Load(this.StateTracker.InstanceId);
            this.IsLoaded = true;
        }

        /// <summary>
        ///   The new.
        /// </summary>
        public void New()
        {
            this.CreateWorkflowApplication();
            this.IsLoaded = true;
        }

        /// <summary>
        ///   The run.
        /// </summary>
        public void Run()
        {
            this.Host.Run();
        }

        /// <summary>
        ///   The unload.
        /// </summary>
        public void Unload()
        {
            try
            {
                if (this.IsLoaded)
                {
                    this.Host.Unload();
                    this.IsLoaded = false;
                }
            }
            catch (Exception exception)
            {
                Trace.WriteLine(exception.Message);
            }
        }

        #endregion
    }
}
